package com.sijobe.installer;

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;

/**
 * Handles all of the events which could occur 
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author simo_415
 */
public class ActionHandler {
   public List files;
   public ManifestHandler manifest;

   public static File base;
   private static GuiMain gui;

   public ActionHandler(GuiMain gui) {
      initialiseData();
      ActionHandler.gui = gui;
   }

   /**
    * Initialises the data which the application uses
    * @return True is returned when the data initialisation was successfully completed
    */
   public boolean initialiseData() {
      files = Util.getFilesExceptCurrent();
      File f = Util.getFile("manifest.xml",files);
      if (f == null) {
         return false;
      }
      manifest = new ManifestHandler(f);
      return true;
   }

   /**
    * Starts up a thread which executes a Minecraft.jar backup
    * @param dir - The base directory where Minecraft is installed
    */
   public void backupMCJAR(File dir) {
      base = dir;
      ThreadBackupMCJAR mcj = new ThreadBackupMCJAR(dir);
      try {
         mcj.setCallback(this.getClass().getDeclaredMethod("callbackBackupMCJAR", new Class[]{String.class}));
      } catch (Exception e) {
         e.printStackTrace();
      }
      mcj.start();
   }

   /**
    * This method is used as the callback method when the Minecraft.jar is successfully backed up
    * @param err - If an error occurred this String contains the error message, otherwise null
    */
   public static void callbackBackupMCJAR(String err) {
      if (err != null) {
         gui.sendError(err);
         System.out.println("ERROR MCJAR: " + err);
      } else {
         gui.sendSuccessMessage("Minecraft.jar was successfully backed up");
         System.out.println("Minecraft.jar was successfully backed up to " + 
                  base + "/backup");
      }
   }

   /**
    * Starts up a thread which executes a Minecraft world backup
    * @param dir - The base directory where Minecraft is installed
    */
   public void backupWorlds(File dir) {
      ThreadBackupWorlds mcw = new ThreadBackupWorlds(dir);
      try {
         mcw.setCallback(this.getClass().getDeclaredMethod("callbackBackupWorlds", new Class[]{String.class}));
      } catch (Exception e) { 
         e.printStackTrace();
      }
      mcw.start();
   }

   /**
    * This method is used as the callback method when the Minecraft worlds are successfully backed up
    * @param err - If an error occurred this String contains the error message, otherwise null
    */
   public static void callbackBackupWorlds(String err) {
      if (err != null) {
         gui.sendError(err);
         System.out.println("ERROR MCWORLD: " + err);
      } else {
         gui.sendSuccessMessage("Worlds were successfully backed up");
         System.out.println("Worlds were successfully backed up to " + 
                  base + "/backup/saves");
      }
   }

   /**
    * This method installs the specified files to the specified locations using the manifest file
    * 
    * @param installFiles - The files to install
    * @param installBase - Where the installation files are kept
    * @param destination - The destination base directory
    * @param manifest - The manifest file
    */
   public void install(String project, List installFiles, File installBase, File destination, ManifestHandler manifest, boolean backupJAR, boolean backupWorld) { 
      base = installBase;
      if (backupJAR) {
         System.out.println("Backing up your Minecraft.jar...");
         callbackBackupMCJAR(ThreadBackupMCJAR.backupMinecraftJar(destination));
      }
      if (backupWorld) {
         System.out.println("Backing up your Minecraft worlds...");
         callbackBackupWorlds(ThreadBackupWorlds.backupWorlds(destination));
      }
      System.out.println("Beginning installation...");
      callbackInstall(ThreadInstall.install(project,installFiles,installBase,destination,manifest));
   }

   /**
    * This method is used as the callback method when the Install is successful
    * 
    * @param err - If an error occurred this String contains the error message, otherwise null
    */
   public static void callbackInstall(String err) {
      if (err != null) {
         gui.sendError("Installation failed, see advanced for more information");
         System.out.println("ERROR - INSTALLATION FAILED: " + err);
      } else {
         gui.sendSuccessMessage("Installation was successful");
         System.out.println("Installation was successful");
      }
      gui.installMod(false);
   }

   /**
    * Starts Minecraft up using a process builder based off the Minecraft
    * installation directory
    * 
    * TODO: Test this works on various OSs. Currently tested on Windows XP
    * TODO: Work out a better way of creating the process
    * 
    * @param dir - The Minecraft installation directory
    */
   public void startMinecraft(File dir) {
      try
      {
         Vector params = new Vector();
         if (System.getProperty("os.name").toLowerCase().contains("win")) {
            // Setup windows startup command
            params.add("javaw");
            params.add("-Xmx1024m");
            params.add("-classpath");
            params.add("Minecraft.jar;lwjgl.jar;lwjgl_util.jar;jinput.jar");
            params.add("-Djava.library.path=\"natives\"");
            params.add("net.minecraft.client.Minecraft");
         } else if (System.getProperty("os.name").toLowerCase().contains("mac")) {
            // Setup MAC startup command
            params.add("javaw");
            params.add("-Xmx1024m");
            params.add("-Xincgc");
            params.add("-classpath");
            params.add("Minecraft.jar:lwjgl.jar:lwjgl_util.jar:jinput.jar");
            params.add("-Dorg.lwjgl.librarypath=\"./natives\"");
            params.add("-Dnet.java.games.input.librarypath=\"$./natives\"");
            params.add("net.minecraft.client.Minecraft");
         } else {
            // Setup Linux startup command
            params.add("javaw");
            params.add("-Xmx1024m");
            params.add("-Xincgc");
            params.add("-classpath");
            params.add("Minecraft.jar:lwjgl.jar:lwjgl_util.jar:jinput.jar");
            params.add("-Dorg.lwjgl.librarypath=\"./natives\"");
            params.add("-Dnet.java.games.input.librarypath=\"./natives\"");
            params.add("net.minecraft.client.Minecraft");
         }

         if (params.size() > 0) {
            ProcessBuilder pb = new ProcessBuilder(params);
            pb.directory(new File(dir,"bin"));
            Process process = pb.start();
            if(process == null) {
               throw new Exception("Process is null");
            }
         }

      } catch(Exception e) {
         e.printStackTrace();
      }
   }
}
